{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c2b8876c",
   "metadata": {},
   "source": [
    "| [01_word_embedding/04_Doc2Vec.ipynb](https://github.com/shibing624/nlp-tutorial/blob/main/01_word_embedding/04_Doc2Vec.ipynb)  | 基于gensim使用Doc2Vec模型  |[Open In Colab](https://colab.research.google.com/github/shibing624/nlp-tutorial/blob/main/01_word_embedding/04_Doc2Vec.ipynb) |\n",
    "\n",
    "# Doc2Vec\n",
    "\n",
    "上一节讲了Word2Vec可以用来训练词向量，那么句子向量怎么训练呢？\n",
    "\n",
    "那这一节就看下如何训练句向量。\n",
    "\n",
    "构建句子向量有比较多的方法，比较流行的是：\n",
    "- bag-of-words词袋模型\n",
    "- 基于word2vec计算句子中各个词语的词向量，然后加和平均得到句子向量\n",
    "- 使用doc2vec训练句向量模型\n",
    "\n",
    "说下这几个模型的优缺点：\n",
    "1. 词袋模型\n",
    "词袋模型存在两个主要的缺点：一个是词袋模型忽略词序，如果两个不同的句子由相同的词但是顺序不同组成，词袋模型会将这两句话定义为同一个表达；另一个是词袋模型忽略了句法，这样训练出来的模型会造成类似‘powerful‘，‘strong’和‘Paris’的距离是相同的，而其实‘powerful’应该相对于’Paris‘距离’strong‘更近才对。\n",
    "\n",
    "2. word2vec\n",
    "比较简单，没有考虑句子词语之间的相互语义关系，我写过一个开源实现：[text2vec](https://github.com/shibing624/text2vec)\n",
    "\n",
    "3. doc2vec\n",
    "本节的重点，下面介绍doc2vec模型。\n",
    "\n",
    "\n",
    "\n",
    "Doc2vec又叫Paragraph Vector是Tomas Mikolov基于word2vec模型提出的，其具有一些优点，比如不用固定句子长度，接受不同长度的句子做训练样本，Doc2vec是一个无监督学习算法，该算法用于预测一个向量来表示不同的文档，该模型的结构潜在的克服了词袋模型的缺点。\n",
    "\n",
    "Doc2vec也有两种训练方式，一种是PV-DM（Distributed Memory Model of paragraph vectors）类似于word2vec中的CBOW模型，另一种是PV-DBOW（Distributed Bag of Words of paragraph vector类似于Word2vec中的skip-gram模型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "10e0b6c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from gensim.models.doc2vec import Doc2Vec, TaggedDocument\n",
    "\n",
    "\n",
    "def get_datasest():\n",
    "    with open(\"data/C000008_test.txt\", 'r', encoding='utf8') as cf:\n",
    "        docs = cf.readlines()\n",
    "        print('docs size:', len(docs))\n",
    "\n",
    "    x_train = []\n",
    "\n",
    "    for i, text in enumerate(docs):\n",
    "        word_list = text.split()\n",
    "        l = len(word_list)\n",
    "        word_list[l - 1] = word_list[l - 1].strip()\n",
    "        document = TaggedDocument(word_list, tags=[i])\n",
    "        x_train.append(document)\n",
    "\n",
    "    return x_train\n",
    "\n",
    "\n",
    "def get_vecs(model, corpus, size):\n",
    "    vecs = [np.array(model.docvecs[z.tags[0]].reshape(1, size))\n",
    "            for z in corpus]\n",
    "    return np.concatenate(vecs)\n",
    "\n",
    "\n",
    "def train(x_train):\n",
    "    model_dm = Doc2Vec(x_train, min_count=1, window=3,\n",
    "                       sample=1e-3, negative=5, workers=4)\n",
    "    model_dm.train(x_train, total_examples=model_dm.corpus_count, epochs=70)\n",
    "    model_dm.save('model_dm')\n",
    "\n",
    "    return model_dm\n",
    "\n",
    "\n",
    "def infer(test_text):\n",
    "    model_dm = Doc2Vec.load(\"model_dm\")\n",
    "    infer_vector_dm = model_dm.infer_vector(test_text)\n",
    "    sims = model_dm.dv.most_similar([infer_vector_dm], topn=10)\n",
    "\n",
    "    return sims"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "cae5d99c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "docs size: 4\n"
     ]
    },
    {
     "data": {
      "text/plain": "[TaggedDocument(words=['1,本报记者', '发自', '上海', '国外', '媒体', '昨日', '报道', '澳大利亚', '银行', 'acq', 'arie', '预计', '推出', '中国', '人民币', '10', '亿元', '商业', '住房', '抵押', '贷款', '资产', '证券化', '计划', '有关部门', '批准', '将是', '海外', '资金', '首次', '此项', '计划', '市场分析', '人士', '计划', '预计', '中国', '监管部门', '阻力', '考虑到', '交易', '相关', '高昂', '固定成本', '人民币', '10', '亿元', '可能是', '最低', '金额', '银行', '原本', '计划', '2006', '年初', '中国', '推出', 'macquarie', 'anda', '房地产', '投资信托', '计划', '香港特区', '证监会', '否决', '该银行', '中国', '房地产投资', '基金', '首席', '投资', '执行官', '此前', '开发商', '行列', '竟是', '金融机构', '项目', '投融资', '资本运作', '才是', '特长'], tags=[0])]"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_train = get_datasest()\n",
    "x_train[:1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "83438d61",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "<gensim.models.doc2vec.Doc2Vec at 0x7f8cf7f6fd90>"
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model_dm = train(x_train)\n",
    "model_dm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3c8e0524",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "[(0, 0.9997050762176514),\n (2, 0.9970113635063171),\n (3, 0.9969313144683838),\n (1, 0.9914861917495728)]"
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_text = ['上海', '国外', '媒体', '昨日', '报道', '澳大利亚', '银行', 'acq',\n",
    "             '开发商', '行列', '竟是', '金融机构', '项目', '投融资', '资本运作', ]\n",
    "\n",
    "sims = infer(test_text)\n",
    "sims"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "26851f6f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9997050762176514 1,本报记者 发自 上海 国外 媒体 昨日 报道 澳大利亚 银行 acq arie 预计 推出 中国 人民币 10 亿元 商业 住房 抵押 贷款 资产 证券化 计划 有关部门 批准 将是 海外 资金 首次 此项 计划 市场分析 人士 计划 预计 中国 监管部门 阻力 考虑到 交易 相关 高昂 固定成本 人民币 10 亿元 可能是 最低 金额 银行 原本 计划 2006 年初 中国 推出 macquarie anda 房地产 投资信托 计划 香港特区 证监会 否决 该银行 中国 房地产投资 基金 首席 投资 执行官 此前 开发商 行列 竟是 金融机构 项目 投融资 资本运作 才是 特长 \n",
      "0.9970113635063171 2,美国 太空 网站 4月 27日 报道 5月 12日 14日 之间 73p 瓦斯 3号 彗星 30 碎片 史无前例 地球 对此 美国 宇航局 科学家 反驳 碎片 撞击 地球 更不 会引起 大规模 海啸 生物 灭绝 灾难 美国 宇航局 科学家 5月 12日 5月 28日 之间 即便是 73p 瓦斯 3号 彗星 最接近 地球 轨道 距离 地球 碎片 地球 月球 距离 20 多倍 不会有 危险 科学家 提醒 利用 会对 彗星 观察 科学家 预计 碎片 中最 明亮 碎片 双筒望远镜 肉眼 观察到 n101 \n",
      "0.9969313144683838 3,化妆品 改善 皮肤 状况 表皮 角质化 过程 所需 时间 化妆品 三个月 会把 理想 皮肤 安全地 改善 预期 短期 化妆品 都是 加了 违禁 原料 皮肤 虽然在 天内 改善 很可能 导致 皮肤病 2. 植物 绿色 化妆品 作成 形态 装在 瓶子 出售 化妆品 不可能 不含 防腐剂 化学成分 迷信 化妆品 植物 纯天然 宣传 3. 化妆品 质量 越好 对照 成分 也许 发现 的产品 便宜 的产品 相差无几 的产品 配方 便宜 选购 化妆品 简单 办法 尝试 检测 合格 品牌 选择 不良反应 感觉 最舒服 那一 \n",
      "0.9914861917495728 2,复旦 新浪 本报记者 杨国强 1984年 相貌端正 复旦大学 新闻系 大学 同学 回忆说 内向 做事 很有 生活 学习 很有 计划性 大学毕业 上海 电视台 当了 两年 记者 赴美 求学 先在 奥克拉荷 大学 拿了 新闻学 硕士 再到 德州 奥斯汀 大学 拿了 财务 专业 硕士 转入 企业界 早就 美国 会计师 协会 美国 注册会计师 1993 1999 普华永道 工作 负责 硅谷 地区 高科技公司 提供 审计 服务 商业 咨询 在此期间 参与 多家 高科技公司 上市 1999 2000 财务 副总裁 身份 加盟 新浪 运作 新浪 美国 上市 参与 设计 中国 互联网 公司 海外 上市 结构 新浪 余家 中国概念股 上市 提供 借鉴 2001年 担任 新浪 cfo 2000 2001 推动 新浪 变了 照搬 美国 网络广告 销售 方式 改为 符合 中国 广告主 需求 时段 流量 模式 广告 主和 客户 肯定 这一 举措 新浪 互联网 广告 市场 领先地位 奠定 基础 2003年 主持 谈判 两次 并购 新浪 无线 市场 后来居上 稳定的 利润 2004年 6月 兼任 新浪 联席 营长 负责 网站 运营 广告 销售 市场 广告 销售 部门 重组 进了 系统化 销售 管理体系 新浪 2005年 广告 销售 业绩 增长率 年来 首次 超过 竞争对手 推动 博客 发展计划 赢得了 新浪博客 成功 2005 年度 中国 杰出 cfo 2005 年度 中国 广告 影响力 人物 荣誉 2005年 9月 升任 新浪 裁并 兼任 首席 财务 2006年 5月 10日 担任 新浪 ceo \n"
     ]
    }
   ],
   "source": [
    "for index, sim_score in sims:\n",
    "    sentence = x_train[index]\n",
    "    words = ''\n",
    "    for word in sentence[0]:\n",
    "        words = words + word + ' '\n",
    "    print(sim_score, words)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2b409c8",
   "metadata": {},
   "source": [
    "本次使用的数据集为样本较少，样本内容比较单一，所以训练出来的结果区分度不大，我线下用2000条情感分析样本效果还可以。doc2vec提取句子向量用于情感分析是可行的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "f1100d7c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.remove('model_dm')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de1d9ae5",
   "metadata": {},
   "source": [
    "本节完。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b2761ef9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}